/**
 * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package fr.smile.liferay.portlet.news.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.mail.internet.InternetAddress;

import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.mail.MailMessage;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.Company;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.Organization;
import com.liferay.portal.model.Role;
import com.liferay.portal.model.User;
import com.liferay.portal.model.UserGroup;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.portlet.PortletProps;

import fr.smile.liferay.portlet.news.model.NewsEntry;
import fr.smile.liferay.portlet.news.service.base.NewsEntryLocalServiceBaseImpl;

/**
 * The implementation of the news entry local service.
 * 
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy
 * their definitions into the {@link fr.smile.liferay.portlet.news.service.NewsEntryLocalService} interface.
 * </p>
 * 
 * <p>
 * Never reference this interface directly. Always use
 * {@link fr.smile.liferay.portlet.news.service.NewsEntryLocalServiceUtil} to access the news entry local service.
 * </p>
 * 
 * <p>
 * This is a local service. Methods of this service will not have security checks based on the propagated JAAS
 * credentials because this service can only be accessed from within the same VM.
 * </p>
 * 
 * @author Brian Wing Shun Chan
 * @see fr.smile.liferay.portlet.news.service.base.NewsEntryLocalServiceBaseImpl
 * @see fr.smile.liferay.portlet.news.service.NewsEntryLocalServiceUtil
 */
public class NewsEntryLocalServiceImpl extends NewsEntryLocalServiceBaseImpl {
	private static final String PROP_BODY = "news.email.body";
	private static final String PROP_SUBJECT = "news.email.subject";
	private static final String PROP_TO_ADDRESS = "news.email.to.address";
	private static final String PROP_TO_NAME = "news.email.to.name";
	private static final String PROP_FROM_ADDRESS = "news.email.from.address";
	private static final String PROP_FROM_NAME = "news.email.from.name";
	private static final String PROP_CHECK_INTERVAL = "news.entry.check.interval";

	private long _entryCheckInterval = GetterUtil.getInteger(PortletProps.get(PROP_CHECK_INTERVAL)) * Time.MINUTE;
	private String _fromName = PortletProps.get(PROP_FROM_NAME);
	private String _fromAddress = PortletProps.get(PROP_FROM_ADDRESS);
	private String _toName = PortletProps.get(PROP_TO_NAME);
	private String _toAddress = PortletProps.get(PROP_TO_ADDRESS);
	private String _subjectPath = PortletProps.get(PROP_SUBJECT);
	private String _bodyPath = PortletProps.get(PROP_BODY);

	public NewsEntry addEntry(long userId, long classNameId, long classPK,
			String title, String description, String content,
			Date displayDate, Date expirationDate) throws PortalException, SystemException {

		// Entry
		User user = userPersistence.findByPrimaryKey(userId);

		Date now = new Date();

		long entryId = counterLocalService.increment();

		NewsEntry entry = newsEntryPersistence.create(entryId);

		entry.setCompanyId(user.getCompanyId());
		entry.setUserId(user.getUserId());
		entry.setUserName(user.getFullName());
		entry.setCreateDate(now);
		entry.setModifiedDate(now);
		entry.setClassNameId(classNameId);
		entry.setClassPK(classPK);
		entry.setTitle(title);
		entry.setDescription(description);
		entry.setContent(content);
		entry.setDisplayDate(displayDate);
		entry.setExpirationDate(expirationDate);

		newsEntryPersistence.update(entry, false);

		return entry;
	}

	public NewsEntry updateEntry(long entryId,
			String title, String description, String content,
			Date displayDate, Date expirationDate) throws PortalException, SystemException {

		// Entry
		NewsEntry entry = newsEntryPersistence.findByPrimaryKey(entryId);

		entry.setModifiedDate(new Date());
		entry.setTitle(title);
		entry.setDescription(description);
		entry.setContent(content);
		entry.setDisplayDate(displayDate);
		entry.setExpirationDate(expirationDate);

		newsEntryPersistence.update(entry, false);

		// Flags
		newsFlagLocalService.deleteFlags(entry.getEntryId());

		return entry;
	}

	public void deleteEntry(NewsEntry entry) throws PortalException, SystemException {
		// Entry
		newsEntryPersistence.remove(entry);

		// Flags
		newsFlagLocalService.deleteFlags(entry.getEntryId());
	}

	public void deleteEntry(long entryId) throws PortalException, SystemException {
		NewsEntry entry = newsEntryPersistence.findByPrimaryKey(entryId);
		deleteEntry(entry);
	}

	public List<NewsEntry> findUnread(long userId, Map<Long, long[]> scopes, int start, int end) throws SystemException {
		return newsEntryFinder.findUnread(userId, scopes, start, end);
	}

	public int countUnread(long userId, Map<Long, long[]> scopes) throws SystemException {
		return newsEntryFinder.countUnread(userId, scopes);
	}

	public List<NewsEntry> findAll(long classNameId, long classPK, int start, int end) throws SystemException {
		return newsEntryPersistence.findByC_C(classNameId, classPK, start, end);
	}

	public int countAll(long classNameId, long classPK) throws SystemException {
		return newsEntryPersistence.countByC_C(classNameId, classPK);
	}

	public void checkEntries() throws PortalException, SystemException {
		Date now = new Date();
		
		List<NewsEntry> published = newsEntryFinder.findPublishedBetween(now, new Date(now.getTime() - _entryCheckInterval));
		for (NewsEntry entry : published) {
			try {
				notifyUsers(entry);
			} catch (IOException e) {
				throw new SystemException(e);
			}
		}
	}

	protected void notifyUsers(NewsEntry entry) throws PortalException, SystemException, IOException {
		
		Company company = companyPersistence.findByPrimaryKey(entry.getCompanyId());

		String className = entry.getClassName();
		long classPK = entry.getClassPK();

		String fromName = _fromName;
		String fromAddress = _fromAddress;
		String toName = _toName;
		String toAddress = _toAddress;

		List<User> users = null;

		if (User.class.getName().equals(className)) {
			User user = userLocalService.getUserById(classPK);

			toName = user.getFullName();
			toAddress = user.getEmailAddress();
			users = Validator.isNotNull(toAddress) ? Collections.singletonList(user) : Collections.<User> emptyList();
		} else if (classPK >= 0) {
			LinkedHashMap<String, Object> params = new LinkedHashMap<String, Object>();
			if (Group.class.getName().equals(className)) {
				Group group = groupPersistence.findByPrimaryKey(classPK);

				toName = group.getName();
				params.put("usersGroups", classPK);
			} else if (Organization.class.getName().equals(className)) {
				Organization organization = organizationPersistence.findByPrimaryKey(classPK);

				toName = organization.getName();
				params.put("usersOrgs", classPK);
			} else if (Role.class.getName().equals(className)) {
				Role role = rolePersistence.findByPrimaryKey(classPK);

				toName = role.getName();
				params.put("usersRoles", classPK);
			} else if (UserGroup.class.getName().equals(className)) {
				UserGroup userGroup = userGroupPersistence.findByPrimaryKey(classPK);

				toName = userGroup.getName();
				params.put("usersUserGroups", classPK);
			}
			users = userLocalService.search(company.getCompanyId(), null, Boolean.TRUE, params, QueryUtil.ALL_POS,
					QueryUtil.ALL_POS, (OrderByComparator) null);
		}

		if (users==null || users.isEmpty()) {
			return;
		}

		List<InternetAddress> bulkAddresses = new ArrayList<InternetAddress>(users.size());
		for (User user : users) {
			InternetAddress address = new InternetAddress(user.getEmailAddress(), user.getFullName());
			bulkAddresses.add(address);
			System.out.println("Email: "+user.getEmailAddress());
		}

		String subject = prepareFromTemplate(_subjectPath, entry, company, fromName, fromAddress, toName, toAddress);
		String body = prepareFromTemplate(_bodyPath, entry, company, fromName, fromAddress, toName, toAddress);

		InternetAddress from = new InternetAddress(fromAddress, fromName);
		InternetAddress to = new InternetAddress(toAddress, toName);
		InternetAddress[] bulkAddressesArray = bulkAddresses.toArray(new InternetAddress[bulkAddresses.size()]);

		MailMessage message = new MailMessage(from, to, subject, body, true);
		message.setBulkAddresses(bulkAddressesArray);

		mailService.sendEmail(message);
	}

	protected String prepareFromTemplate(String path, NewsEntry entry, Company company, String fromName, String fromAddress,
			String toName, String toAddress) throws IOException {
		String defaultLocale = entry.getDefaultLocale();
		
		String template = StringUtil.read(getClass().getClassLoader(), path);
		String result = StringUtil.replace(
				template,
				new String[] {
					"[$ENTRY_CONTENT$]",
					"[$ENTRY_ID$]",
					"[$ENTRY_TITLE$]",
					 "[$ENTRY_URL$]",
					"[$FROM_ADDRESS$]",
					"[$FROM_NAME$]",
					"[$PORTAL_URL$]",
					"[$TO_ADDRESS$]",
					"[$TO_NAME$]"
				},
				new String[] {
					entry.getContentByLocale(defaultLocale),
					String.valueOf(entry.getEntryId()),
					entry.getTitleByLocale(defaultLocale),
					"http://"+company.getVirtualHost()+":"+PortalUtil.getPortalPort(),
					fromAddress,
					fromName,
					company.getVirtualHost(),
					toAddress,
					toName
				});
		return result;
	}

}
